package com.atguigu.lease.common.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * MD5加密工具类
 * 提供字符串加密、文件校验、字节数组加密等功能
 */
public class MD5Util {

    private static final char[] HEX_DIGITS = {
            '0', '1', '2', '3', '4', '5', '6', '7',
            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
    };

    /**
     * 对字符串进行MD5加密（默认UTF-8编码）
     * @param input 原始字符串
     * @return 32位小写MD5值，输入为空时返回空字符串
     */
    public static String encrypt(String input) {
        if (input == null) return "";
        return encrypt(input.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 对字节数组进行MD5加密
     * @param bytes 原始字节数组
     * @return 32位小写MD5值，输入为空时返回空字符串
     */
    public static String encrypt(byte[] bytes) {
        if (bytes == null) return "";
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(bytes);
            return bytesToHex(digest);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5 algorithm not available", e);
        }
    }

    /**
     * 计算文件的MD5值
     * @param file 目标文件
     * @return 32位小写MD5值，文件不存在时返回空字符串
     */
    public static String encrypt(File file) {
        if (file == null || !file.exists() || !file.isFile()) {
            return "";
        }

        try (InputStream fis = new FileInputStream(file)) {
            return encrypt(fis);
        } catch (IOException e) {
            throw new RuntimeException("File read error", e);
        }
    }

    /**
     * 计算输入流的MD5值（不关闭流）
     * @param inputStream 输入流
     * @return 32位小写MD5值
     */
    public static String encrypt(InputStream inputStream) throws IOException {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] buffer = new byte[8192];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                md.update(buffer, 0, length);
            }
            return bytesToHex(md.digest());
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5 algorithm not available", e);
        }
    }

    /**
     * 验证字符串MD5值
     * @param input 原始字符串
     * @param md5Value 预期的MD5值
     * @return 是否匹配
     */
    public static boolean verify(String input, String md5Value) {
        return encrypt(input).equalsIgnoreCase(md5Value);
    }

    /**
     * 验证文件MD5值
     * @param file 目标文件
     * @param md5Value 预期的MD5值
     * @return 是否匹配
     */
    public static boolean verify(File file, String md5Value) {
        return encrypt(file).equalsIgnoreCase(md5Value);
    }

    // 字节数组转十六进制字符串
    private static String bytesToHex(byte[] bytes) {
        char[] chars = new char[bytes.length * 2];
        for (int i = 0; i < bytes.length; i++) {
            byte b = bytes[i];
            chars[i * 2] = HEX_DIGITS[(b >>> 4) & 0x0F];
            chars[i * 2 + 1] = HEX_DIGITS[b & 0x0F];
        }
        return new String(chars);
    }
}